trigger CaseNationalOperationsAfter on Case (after insert, after update) {

	// Trigger for National Operations Cases (NATO)

	// Load the Nato record types
	ID ioRecordType = RecordTypeHelper.GetRecordTypeID('Case', 'National Ops - Insertion Order');
	ID crRecordType = RecordTypeHelper.GetRecordTypeID('Case','National Ops - Change Request');	
	CaseTeamHelper cth;

   	// The case triggers are called twice due to workflow. This causes some serious issues since the 
	// new/old trigger objects stay the same for both calls, making it tricky to know if we've already done
	// the work of updatign the case team. Currently, all rep information is updated before the workflows fire
	// so the case teams do not need updating on the second trigger run. 
 	if(CaseTeamHelper.FirstRun){
	    for(Case newCaseObject : Trigger.new) 
	    {    	
	    	// Verify the it's a Change Request or Insertion Order	
		    if ((ioRecordType == newCaseObject.RecordTypeId) || (crRecordType == newCaseObject.RecordTypeId)){
	
				// Initialize the CaseTeamHelper only when needed
				if(null == cth) cth = new CaseTeamHelper();
								
								
				if(trigger.isInsert){
					// Add the case team members
					RefreshCaseTeam(new Set<ID>{
										newCaseObject.Nato_Rep_SS__c, 
										newCaseObject.NATO_Rep_OV__c,
										newCaseObject.Order_Entry__c,
										newCaseObject.Ad_Production__c,
										newCaseObject.Quality_Control__c,
										newCaseObject.Nato_Rep_QC2__c,
										newCaseObject.Billing__c}, 
									new Set<ID>{}, 
									newCaseObject.ID);
				}	    	
	
		    	if(trigger.isUpdate){
					// Refresh the case team members
			    	Case oldCaseObject = trigger.oldMap.get(newCaseObject.ID);
					RefreshCaseTeam(new Set<ID>{
										newCaseObject.Nato_Rep_SS__c, 
										newCaseObject.NATO_Rep_OV__c,
										newCaseObject.Order_Entry__c,
										newCaseObject.Ad_Production__c,
										newCaseObject.Quality_Control__c,
										newCaseObject.Nato_Rep_QC2__c,
										newCaseObject.Billing__c}, 
									new Set<ID>{
										oldCaseObject.Nato_Rep_SS__c, 
										oldCaseObject.NATO_Rep_OV__c,
										oldCaseObject.Order_Entry__c,
										oldCaseObject.Ad_Production__c,
										oldCaseObject.Quality_Control__c,
										oldCaseObject.Nato_Rep_QC2__c,
										oldCaseObject.Billing__c}, 
									newCaseObject.ID);
		    	}	    		
		    }		    
	    }

		// Save the case team changes	    
	    if(cth != null)
    		cth.SaveToDatabase();	    
	}
    else
    	System.Debug('Not refreshing Case Teams on second trigger run.');
    
    // RefreshCaseTeam - refreshes the case team members
    // Parameters: 
    //		newCaseTeam - the set of user ids that should be on the case team
    //		oldCaseTeam - the set of user ids that were on the case team
    //		caseId - the case id
    private void RefreshCaseTeam(Set<ID> newCaseTeam, Set<ID> oldCaseTeam, ID caseId){
    	Set<ID> membersToAdd = new Set<ID>();
    	boolean hasMembersToRemove = false;
    	
    	// The sets might have null users - remove them.
    	newCaseTeam.remove(null);
    	oldCaseTeam.remove(null);
    	
    	for(ID oldTeamMember : oldCaseTeam){
    		// If a user was previously on the case team but isn't anymore we will completly rebuild the case team
    		// instead of trying to figure out which records need to be removed. 
    		if(!newCaseTeam.contains(oldTeamMember)){
				hasMembersToRemove = true;
				break;    		
    		}	   			    		
    	}
    	
    	if (!hasMembersToRemove){
    		// Only add the new users
	    	for(ID newTeamMember : newCaseTeam){
	    		// If the user was not on the old case team, mark them for addition
	    		if(!oldCaseTeam.contains(newTeamMember))
	    			membersToAdd.add(newTeamMember);   			    		
	    	}
	    	
	    	for(ID memberToAdd : membersToAdd)
		    	cth.AddCaseTeamMember(memberToAdd, caseId, 'Nato Case Team', false);   		    		
    	}else{
    		// Clean out the case team and rebuild it
    		if(oldCaseTeam.size() > 0)
    			cth.RemoveAllUsersFromCaseTeamRole(caseId, 'Nato Case Team');
    		
	    	for(ID memberToAdd : newCaseTeam)
		    	cth.AddCaseTeamMember(memberToAdd, caseId, 'Nato Case Team', false);   		    		
    	}    	
    }
    
}